import * as ws from 'websocket'
import * as http from 'http';
import { BaseServer } from '../framework/BaseServer';
import { HandleHeart } from './handle/HandleHeart';
import { DebugClient } from './DebugClient';
import { HandleRegist } from './handle/HandleRegist';
import { EClientState } from '../framework/common/EClientState';
import ArrayEx from '../../LTGame/Utils/ArrayEx';
import { HandleC1002 } from './handle/HandleC1002';
import { HandleC1003 } from './handle/HandleC1003';
import { HandleC1004 } from './handle/HandleC1004';

export class DebugHost extends BaseServer {

    public tag: string = 'DebugHost';

    private _port: number;
    private _wsServer: ws.server;

    private _clientList: DebugClient[];
    public get clientList(): DebugClient[] {
        return this._clientList;
    }

    constructor(port: number) {
        super();
        this.updateTime = 0;
        this._port = port;
        this._clientList = [];
    }

    async _OnInit(): Promise<void> {
        return new Promise((resolve) => {
            this._Start(resolve);
        });
    }

    private async _Start(cb: any) {

        this._RegistMsgHandle(new HandleHeart(this));
        this._RegistMsgHandle(new HandleRegist(this));
        this._RegistMsgHandle(new HandleC1002(this));
        this._RegistMsgHandle(new HandleC1003(this));
        this._RegistMsgHandle(new HandleC1004(this));

        let server = http.createServer((request, response) => {
            this.Log('Received request for ' + request.url);
            response.writeHead(404);
            response.end();
        });
        server.listen(this._port, () => {
            this.Log('Server is listening on port:' + this._port);
            cb();
        });

        this._wsServer = new ws.server({
            httpServer: server,
            // You should not use autoAcceptConnections for production
            // applications, as it defeats all standard cross-origin protection
            // facilities built into the protocol and the browser.  You should
            // *always* verify the connection's origin and decide whether or not
            // to accept it.
            autoAcceptConnections: false,
            maxReceivedFrameSize: 1024 * 1024 * 1024 * 1024,
            maxReceivedMessageSize: 1024 * 1024 * 1024 * 1024,
        });

        this._wsServer.on('request', (request) => {
            this._OnRequest(request);
        });
    }

    private _OnRequest(request: ws.request) {
        if (!this._CheckOriginIsAllowed(request.origin)) {
            request.reject();
            this.Log('Connection from origin ' + request.origin + ' rejected.');
            return;
        }

        let connection = request.accept('echo-protocol', request.origin);
        this.Log('Connection from origin ' + request.origin + ' accepted.');

        let client = new DebugClient(connection, this);
        client.Init();
        this._clientList.push(client);
    }

    private _CheckOriginIsAllowed(origin: string) {
        // put logic here to detect whether the specified origin is allowed.
        return true;
    }

    _OnLogicUpdate() {
        // 清理已断开连接的客户端
        for (let i = 0; i < this._clientList.length; ++i) {
            let unregistClient = this._clientList[i];
            if (unregistClient.state == EClientState.Closed) {
                ArrayEx.RemoveAt(this._clientList, i--);;
            }
        }

        // 检查debugger
        for (let i = 0; i < this._clientList.length; ++i) {
            let debuggerClient = this._clientList[i];
            debuggerClient.CheckPairAlive();
        }
    }

    public SearchClient(clientId: number): DebugClient {
        for (let client of this._clientList) {
            if (client.id == clientId) {
                return client;
            }
        }
        return null;
    }

    public ConnectPair(client: DebugClient, deb: DebugClient): boolean {
        client.pair = deb;
        deb.pair = client;
        return true;
    }

}